﻿using System;
using System.Linq;
using System.Reflection;

namespace common {

	using i_core;
	using Autofac;
	using Autofac.Core;
	using System.Collections.Generic;

	public class autofac_reg {

		public static void reg_interface<T>(e_instance_life ise_life = e_instance_life.PerDependency) where T : i_dependency {
			Type s_type = null;
			foreach (var assembly in get_all_assembly()) {
				var ss = assembly.GetTypes();
				if ((s_type = assembly.GetTypes().FirstOrDefault(t => typeof(T).IsAssignableFrom(t) && !t.IsAbstract)) == null)
					continue;
				break;
			}
			if (s_type == null)
				return;
			switch (ise_life) {
				case e_instance_life.PerDependency: global_vars.builder.RegisterType(s_type).AsImplementedInterfaces().InstancePerDependency(); break;
				case e_instance_life.PerLifetimeScope: global_vars.builder.RegisterType(s_type).AsImplementedInterfaces().InstancePerLifetimeScope(); break;
				case e_instance_life.PerMatchingLifetimeScope: global_vars.builder.RegisterType(s_type).AsImplementedInterfaces().InstancePerMatchingLifetimeScope(); break;
				case e_instance_life.SingleInstance: global_vars.builder.RegisterType(s_type).AsImplementedInterfaces().SingleInstance(); break;
				default: break;
			}
		}

		public static void reg_key<T>(string key_name = "type") {
			var types = get_all_type();

			global_vars.builder.RegisterTypes(types.ToArray()).Keyed<T>(
				t => {
					object obj = null;

					foreach (var assembly in get_all_assembly()) {
						if ((obj = assembly.CreateInstance(t.FullName)) == null)
							continue;
						else
							break;
					}
					if (obj == null)
						return null;
					return get_t_type(obj, key_name.ToString());
				}).InstancePerDependency();
		}

		public static void reg_key<T>(string key_name, e_instance_life ise_life = e_instance_life.PerDependency) {
			var types = get_all_type();

			var builder_type = global_vars.builder.RegisterTypes(types.ToArray()).Keyed<T>(
				t => {
					object obj = null;

					foreach (var assembly in get_all_assembly()) {
						if ((obj = assembly.CreateInstance(t.FullName)) == null)
							continue;
						else
							break;
					}
					if (obj == null)
						return null;
					return get_t_type(obj, key_name.ToString());
				});
			switch (ise_life) {
				case e_instance_life.PerDependency: builder_type.InstancePerDependency(); break;
				case e_instance_life.PerLifetimeScope: builder_type.InstancePerLifetimeScope(); break;
				case e_instance_life.PerMatchingLifetimeScope: builder_type.InstancePerMatchingLifetimeScope(); break;
				case e_instance_life.SingleInstance: builder_type.SingleInstance(); break;
				default: break;
			}
		}

		private static T get_t_type<T>(T model, string p_name) {
			var t = model.GetType();
			var PropertyList = t.GetProperties();
			var t_value = new object();
			foreach (var item in PropertyList) {
				if (item.Name == p_name)
					t_value = item.GetValue(model, null);
			}
			return (T)t_value;
		}


		private static Assembly[] get_all_assembly() {
			var _AssemblyList = new List<Assembly>();
			var _AssemblyList_clone = new List<Assembly>() {
				 Assembly.LoadFrom(@"i_core.dll"),
				 Assembly.LoadFrom(@"client.exe"),
				 Assembly.LoadFrom(@"m_log.dll"),
				 Assembly.LoadFrom(@"common.dll"),
				 Assembly.LoadFrom(@"db_model.dll"),
				 Assembly.LoadFrom(@"db_util.dll")
		};
			//foreach (var assembly in _AssemblyList_clone) {
			//    var cus_attr = assembly.GetCustomAttribute(typeof(custom_attribute)) as custom_attribute;
			//    if (cus_attr != null && cus_attr.ascription == "personal") {
			//        _AssemblyList.Add(assembly);
			//    }
			//}
			return _AssemblyList_clone.ToArray();
		}

		private static Type[] get_all_type() {
			List<Type> list_t = new List<Type>();
			foreach (var assembly in get_all_assembly()) {
				foreach (var type in assembly.GetTypes())
					list_t.Add(type);
			}
			return list_t.ToArray();
		}
	}

	public enum e_instance_life {
		/// <summary>
		/// configure the component so that every dependent component or call to Resolve() gets a new, unique instance (default.) 
		/// </summary>
		PerDependency,

		/// <summary>
		/// configure the component so that every dependent component or call to Resolve() within a single ILifetimeScope gets the same, shared instance. Dependent components in different lifetime scopes will get different instances. 
		/// </summary>
		PerLifetimeScope,

		/// <summary>
		/// configure the component so that every dependent component or call to Resolve() within a ILifetimeScope tagged with any of the provided tags value gets the same, shared instance. Dependent components in lifetime scopes that are children of the tagged scope will share the parent's instance. If no appropriately tagged scope can be found in the hierarchy an <seealso cref="DependencyResolutionException"/> is thrown. 。
		/// </summary>
		PerMatchingLifetimeScope,

		/// <summary>
		/// configure the component so that every dependent component or call to Resolve() within a ILifetimeScope created by an owned instance gets the same, shared instance. Dependent components in lifetime scopes that are children of the owned instance scope will share the parent's instance. If no appropriate owned instance scope can be found in the hierarchy an <seealso cref="DependencyResolutionException"/> is thrown. 。
		/// </summary>
		PerOwned,

		/// <summary>
		/// configure the component so that every dependent component or call to Resolve() gets the same, shared instance.
		/// </summary>
		SingleInstance,

		/// <summary>
		/// share one instance of the component within the context of a single HTTP request. only asp.net mvc
		/// </summary>
		PerRequest
	}
}
